package cn.ycc1.auth.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;

import javax.sql.DataSource;
import java.util.Arrays;

/**
 * @Title:
 * @Author ycc
 * @Date 2023/7/8 16:48
 */
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    @Autowired
    private TokenStore tokenStore;

    @Autowired
    ClientDetailsService clientDetailsService;

    @Autowired
    private AuthorizationCodeServices authorizationCodeServices;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private JwtAccessTokenConverter accessTokenConverter;

    @Autowired
    PasswordEncoder passwordEncoder;

    //将客户端信息存储到数据库
    @Bean
    public ClientDetailsService clientDetailsService(DataSource dataSource) {
        ClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);
        ((JdbcClientDetailsService) clientDetailsService).setPasswordEncoder(passwordEncoder);
        return clientDetailsService;
    }

    //客户端详情服务
    @Override
    public void configure(ClientDetailsServiceConfigurer clients)
            throws Exception {
        clients.withClientDetails(clientDetailsService);
       /* clients.inMemory()// 使用in-memory存储
                .withClient("c1")// client_id
                .secret(new BCryptPasswordEncoder().encode("secret"))//客户端密钥
                .resourceIds("res1")//资源列表
                .authorizedGrantTypes("authorization_code", "password","client_credentials","implicit","refresh_token")// 该client允许的授权类型authorization_code,password,refresh_token,implicit,client_credentials
                .scopes("all")// 允许的授权范围
                .autoApprove(false)//false跳转到授权页面
                //加上验证回调地址
                .redirectUris("http://www.baidu.com")*/
        ;
    }


    //令牌管理服务
    @Bean
    public AuthorizationServerTokenServices tokenService() {
        DefaultTokenServices service=new DefaultTokenServices();
        service.setClientDetailsService(clientDetailsService);//客户端详情服务
        service.setSupportRefreshToken(true);//支持刷新令牌
        service.setTokenStore(tokenStore);//令牌存储策略
        //令牌增强
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        tokenEnhancerChain.setTokenEnhancers(Arrays.asList(accessTokenConverter));
        service.setTokenEnhancer(tokenEnhancerChain);

        service.setAccessTokenValiditySeconds(7200); // 令牌默认有效期2小时
        service.setRefreshTokenValiditySeconds(259200); // 刷新令牌默认有效期3天
        return service;
    }

    //设置授权码模式的授权码如何存取，暂时采用内存方式
/*    @Bean
    public AuthorizationCodeServices authorizationCodeServices() {
        return new InMemoryAuthorizationCodeServices();
    }*/

    @Bean
    public AuthorizationCodeServices authorizationCodeServices(DataSource dataSource) {
        return new JdbcAuthorizationCodeServices(dataSource);//设置授权码模式的授权码如何存取
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
        endpoints
                .authenticationManager(authenticationManager)//认证管理器
                .authorizationCodeServices(authorizationCodeServices)//授权码服务
                .tokenServices(tokenService())//令牌管理服务
                .allowedTokenEndpointRequestMethods(HttpMethod.POST);
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security){
        security
                .tokenKeyAccess("permitAll()")                    //oauth/token_key是公开
                .checkTokenAccess("permitAll()")                  //oauth/check_token公开
                .allowFormAuthenticationForClients()				//表单认证（申请令牌）
        ;
    }

//    @Autowired
//    TokenStore tokenStore;
////    @Autowired
////    private ClientDetailsService clientDetailsService;
//    @Autowired
//    AuthenticationManager authenticationManager;
//    @Autowired
//    private JwtAccessTokenConverter accessTokenConverter;
//
//    @Autowired
//    PasswordEncoder passwordEncoder;
//
//    //将客户端信息存储到数据库
////    @Bean
////    public ClientDetailsService clientDetailsService(DataSource dataSource) {
////        ClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);
////        ((JdbcClientDetailsService) clientDetailsService).setPasswordEncoder(passwordEncoder);
////        return clientDetailsService;
////    }
//
//    /**
//     * 1. 配置客户端详情
//     * @param clients
//     * @throws Exception
//     */
//    public void configure(ClientDetailsServiceConfigurer clients)  throws Exception {
//        // 设置客户端ID和密钥
//        // clients.withClientDetails(clientDetailsService);
//        clients.inMemory()
//                .withClient("ycc1-client")
//                .secret("ycc1-secret")
//                .authorizedGrantTypes("authorization_code", "password","refresh_token")
//                .scopes("read", "write") // 允许的授权范围
//                .autoApprove(false);
//    }
//
//    /**
//     * 2. 配置访问端点和管理服务
//     * 在上面的示例中，我们使用authenticationManager()方法设置授权服务器端点的认证管理器，
//     * 使用tokenStore()方法设置令牌存储，使用accessTokenConverter()方法设置访问令牌转换器。
//     * 接下来，我们使用PasswordEncoder()方法设置密码编码器。
//     * 最后，我们使用configure()方法将授权服务器端点的详细信息传递给Spring容器。
//     * @throws Exception
//     */
//    @Override
//    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
//        // 设置授权服务器端点的URL
//        endpoints.authenticationManager(authenticationManager) // 密码模式需要
// //               .tokenStore(tokenStore())
//                .tokenServices(tokenServices())
//                //.accessTokenConverter(accessTokenConverter())
//                .allowedTokenEndpointRequestMethods(HttpMethod.POST);
//    }
//
//    /**
//     * 令牌管理服务
//     * @return
//     */
//    @Bean
//    public AuthorizationServerTokenServices tokenServices() {
//        DefaultTokenServices service = new DefaultTokenServices();
//        // service.setClientDetailsService(clientDetailsService);
//        service.setSupportRefreshToken(true);
//        service.setTokenStore(tokenStore); // 令牌存储策略
//
//        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
//        tokenEnhancerChain.setTokenEnhancers(Arrays.asList(accessTokenConverter));
//        service.setTokenEnhancer(tokenEnhancerChain);
//
//        service.setAccessTokenValiditySeconds(7200); // 默认有效期2小时
//        service.setRefreshTokenValiditySeconds(259200); // 刷新有效期3天
//
//        return service;
//    }
//
//    @Bean
//    public PasswordEncoder passwordEncoder() {
//        return new BCryptPasswordEncoder();
//    }
//
//
//    /**
//     * 3. 配置访问端点安全约束
//     */
//    @Override
//    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
//        // 设置授权服务器的安全上下文和访问令牌的有效期
//        security.tokenKeyAccess("permitAll()")
//                // .checkTokenAccess("isAuthenticated()");
//                .checkTokenAccess("permitAll()")
//                .allowFormAuthenticationForClients();
//    }
}
